AOE工程实践-Tengine组件
Tengine是由 OPEN AI LAB 开发的一款轻量级模块化高性能神经网络推理引擎,专门针对Arm嵌入式设备优化,并且无需依赖第三方库,可跨平台使用支持Android,Liunx,并支持用GPU、DLA作为硬件加速计算资源异构加速。
Android平台直接集成
为SqueezeNet接入Tengine,需要把相关的模型文件,Tengine的头文件和库,JNI调用,前处理和后处理相关业务逻辑等,都放在SqueezeNet Sample工程里。这样简单直接的集成方法,问题也很明显,和业务耦合比较多,不具有通用性,前处理后处理都和SqueezeTengine这个Sample有关,不能很方便地提供给其他业务组件使用。深入思考一下,如果我们把AI业务,作为一个一个单独的AI组件提供给业务的同学使用,会发生这样的情况:
每个组件都要依赖和包含Tengine的库,而且每个组件的开发同学,都要去熟悉Tengine的接口,写C的调用代码,写JNI,这真的是比较麻烦和头疼的事情。另外当你想要在底层从A推理框架换到B推理框架的时候,还需要去修改底层调用推理框架的部分。所以我们很自然地会想到要提取一个Tengine的组件出来,就像这样:
通过对不同的推理框架的封装,对业务层提供统一的Java层接口来调用。这样调用变得简单了,而且如果要从Tengine组件切换到其他AOE提供的推理框架组件,只要修改依赖的库就可以了,不用再去修改底层AI推理框架的调用代码。
AOE SDK里的Tengine组件
在AOE开源SDK里,我们提供了Android版本的Tengine组件,下面我们从5个方面来讲一讲Tengine组件:
Tengine组件的设计
对SqueezeNet Sample的改造
如何在Native层调用Tengine组件
Tengine组件和AOE SDK的关系
对Tengine组件的一些思考
▌Tengine组件的设计
// 加载Tengine模型
void loadTengineModel(...)
// 初始化是否成功
boolean isLoadModelSuccess()
// 输入rgba数据
void inputRgba(...)
// 单输入进行推理,得到单输出数据
void run(...)
// 多输入进行推理,得到多输出的数据
void runForMultipleInputsOutputs(...)
// 得到推理结果
Tensor getOutputTensor(...)
// 关闭和清理内存
void close()
支持多输入多输出。
使用Object作为输入和输出(支持了ByteBuffer和多维数组)。
使用ByteBuffer来提升效率,支持Direct ByteBuffer。
接口里的字节操作更加便捷,例如里面的putInt,getInt,putFloat,getFloat,flip等一系列接口,可以很方便的对数据进行操作。
和Native层做交互,可以使用DirectByteBuffer,提升效率。我们可以简单理解为java层和native层可以直接对一块“共享”内存进行操作,减少了中间的字节的拷贝过程。以图片为例,输入和输出流程如下图所示:
对SqueezeNet Sample的改造
集成AOE Tengine组件以后,让SqueezeNet依赖Tengine Module,SqueezeNet Sample里面只包含了模型文件,前处理和后处理相关的业务逻辑,前处理和后处理可以用java,也可以用c来实现,由具体的业务实现来决定。新的代码结构变得非常简洁。具体可以参考我们的sample工程。
如何在Native层调用Tengine组件
Tengine自身提供的API,是可以直接在Native层进行调用的。AOESDK,为了更快捷地适配不同的推理框架,我们在Natice层做了一层代理,可以通过引入Tengine组件和头文件的方式,在Native层进行Tengine组件的调用。
Tengine组件和AOE SDK的关系
直接接入
通过AOE SDK接入
3. 对Tengine组件的总结和思考
--------- PUHUI TECH ---------
热爱生活,热爱技术,热爱分享。在即时通讯领域有丰富的经验。我的人生格言是,每天进步一点点。